package com.baizhi.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Configuration
@Aspect
public class RedisAspect {
    @Autowired
    private RedisTemplate redisTemplate;
    /*
    * 添加缓存
    *
    * 在增强中需要添加缓存 意味着需要获取方法查询的结果
    * 环绕增强
    *
    * key 类名 getThis
    * hashkey  方法名+参数
    *
    * 1.获取key和hashkey
    * 2.根据key和发送key看看redis中有没有数据
    * 3.如果有 直接把redis查询的结果返回
    * 4.如果没有  方法放行 查出数据库 将数据库的结果存储在缓存中 并返回
    *
    * */
    @Around("@annotation(com.baizhi.annotation.AddCacheAnnotation)")
    public Object addCache(ProceedingJoinPoint joinPoint) throws Throwable {
        //        1.获取key 和 hashKey
        String key = joinPoint.getThis().toString();
        System.out.println("获取key："+key);

        StringBuffer stringBuffer = new StringBuffer();

//        获取方法名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        stringBuffer.append(methodName);
//        获取方法的形参
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            stringBuffer.append(arg.toString());
        }
//        获取hashKey
        String hashKey = stringBuffer.toString();

        System.out.println("获取hashKey："+hashKey);

//        2.根据key和hashKey 康康redis中有没有数据
        HashOperations opsForHash = redisTemplate.opsForHash();

        Object result = opsForHash.get(key, hashKey);

        if (result==null) {
//            4.如果没有  方法放行 查询数据库 将数据库的结果 存储在缓存中  并返回
//            方法放行 查询数据库
            result = joinPoint.proceed();

//            将数据库的结果 存储在缓存中
            Map map = new HashMap();
            map.put(hashKey,result);

            opsForHash.putAll(key,map);
            System.out.println("获取数据库数据 添加缓存");

//            添加 缓存自动删除  认为缓存长期来看都是不安全的  即便是不手动删除
//            也需要让redis定期自动删除
            /**
             * expire 设置定期自动删除  设置缓存的存活时间
             *
             * 参数1  要设置的key
             * 参数2 时间
             * 参数3 时间的单位
             */
            redisTemplate.expire(key,10, TimeUnit.SECONDS);

            return result;
        }else {
            System.out.println("从缓存中获取数据");
            return result;
        }
    }
    /**
     * 删除缓存 根据key删除 key是当前类的类名
     * 在增删改之前删除 前置增强
     */
    @Before("@annotation(com.baizhi.annotation.DeleteCacheAnnotation)")
    public void deleteCache(JoinPoint joinPoint){
//        1.获取当前类的类名  通过JoinPoint可以拿到连接点相关的数据
        String className = joinPoint.getThis().toString();

//        2.通过类名删除缓存
        redisTemplate.delete(className);
    }

}
